#pragma once

#include <iostream>
#include <queue>
#include "Mutex.hpp"
#include "Cond.hpp"
using namespace LockModule;
using namespace CondModule;

namespace BlockQueueModule
{
    static const int gcap = 10;
    template <typename T>
    class BlockQueue
    {
    private:
    bool IsFull(){return _q.size() == _cap;}
    bool IsEmpty(){return _q.empty();}
 
    public:
        BlockQueue(int cap = gcap):_cap(cap)
        {
           
        }

        void Equeue(const T &in)
        {
            LockGuard lockguard(_mutex);
            pthread_mutex_lock(&_mutex);
            //生产数据是有条件的
            while(IsFull())
            {
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);
                _pwait_num--;

            }
            _q.push();

            if(_cwait_num)
            {
                std::cout<<"唤醒消费者"<<std::endl;
                pthread_cond_signal(&_consumer_cond);
            }
            //pthread_mutex_unlock(&_mutex)
        }

        void Pop(T *out)
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())
            {
                _cwait_num++;
                pthread_cond_wait(&consumer_cond,&_mutex);
                _cwait_num--;
            }
            *out = _q.front();
            _q.pop();

            if(_pwait_num)
            {
                std::cout<<"唤醒生产者"<<std::endl;
                pthread_cond_signal(&productor_cond);
            }
            pthread_mutex_unlock(&_mutex);


        }
        ~BlockQueue()
        {
           
        }

    private:
        int _cwait_num = 0;
        int _pwait_num = 0;
        std::queue<T> _q;               // 保存数据的容器，临界资源
        int _cap;                       // bq最大容量
        Mutex _mutex;         // 互斥
        Cond _productor_cond; // 生产者条件变量
        Cond _consumer_cond;  // 消费者条件变量
    };
}

//version 1
/*#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

namespace BlockQueueModule
{
    static const int gcap = 10;
    template <typename T>
    class BlockQueue
    {
    private:
    bool IsFull(){return _q.size() == _cap;}
    bool IsEmpty(){return _q.empty();}

    public:
        BlockQueue(int cap = gcap):_cap(cap)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_productor_cond, nullptr);
            pthread_cond_init(&_consumer_cond, nullptr);
        }

        void Equeue(const T &in)
        {
            pthread_mutex_lock(&_mutex);
            //生产数据是有条件的
            while(IsFull())
            {
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);
                _pwait_num--;

            }
            _q.push();

            if(_cwait_num)
            {
                std::cout<<"唤醒消费者"<<std::endl;
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex)
        }

        void Pop(T *out)
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())
            {
                _cwait_num++;
                pthread_cond_wait(&consumer_cond,&_mutex);
                _cwait_num--;
            }
            *out = _q.front();
            _q.pop();

            if(_pwait_num)
            {
                std::cout<<"唤醒生产者"<<std::endl;
                pthread_cond_signal(&productor_cond);
            }
            pthread_mutex_unlock(&_mutex);


        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_mutex_destroy(&_productor_cond);
            pthread_mutex_destroy(&_consumer_cond);
        }

    private:
        int _cwait_num = 0;
        int _pwait_num = 0;
        std::queue<T> _q;               // 保存数据的容器，临界资源
        int _cap;                       // bq最大容量
        pthread_mutex_t _mutex;         // 互斥
        pthread_cond_t _productor_cond; // 生产者条件变量
        pthread_cond_t _consumer_cond;  // 消费者条件变量
    };
}*/